Divide et Impera ( Împarte şi stăpâneşte)- tehnica a recursivitatii

Divide – presupune împărţirea unei probleme în 2 sau mai multe subprobleme ( regula de impartire depinde de enunt/cerinta....de logica/spatiul cautarii pentru rezolvarea cerintei) ;
Rezolvă(Calcul efectiv conform cerintei)- rezolvarea independentă a fiecărei subprobleme , fiecare subproblemă având, teoretic, o anumită soluţie;
Impera (stăpâneşte)- combinarea soluţiilor(parţiale) obţinute în etapa anterioara pentru fiecare subproblema ;



I. Exemple didactice ( care nu justifica neaparat utilizarea acestei metode):
suma elementelor dintr-un vector
#include <fstream>

using namespace std;
ifstream f("div.in");
ofstream g("div.out");
int v[100],n;
void divide(int stanga, int dreapta,int &mijloc)
{ mijloc=(stanga+dreapta)/2; }
void impera(int a, int b, int &sol)
{ sol=a+b; }
void calcul(int stanga, int dreapta, int v[], int &sol)
{ int a,b,mijloc;
if(stanga==dreapta)
{ sol=v[stanga]; }
else
{ divide(stanga, dreapta, mijloc);
calcul(stanga, mijloc,v,a);
calcul(mijloc+1, dreapta,v,b);
impera(a,b,sol);
}
}
int main()
{ int i,sol;
f>>n;
for(i=1;i<=n;++i) f>>v[i];
calcul(1,n,v,sol); g<<sol;
f.close(); g.close();
return 0;
}
cmmdc (Algoritmul lui Euclid) dintr-un sir,
atunci singura modificare ar fi la

void impera(int a, int b, int &sol)
{
while(a!=b)
if(a>b)a=a-b;
else b=b-a;
sol=a;

}

Daca dorim sa numaram cate elemente dintr-un sir indeplinesc
o anumita proprietate , modificarea poate fi facuta in subprogramul
calcul de exemplu:

Ex.didactic :pare/impare :
void calcul(int stanga, int dreapta, int v[], int &sol)
{ int a,b,mijloc;
if(stanga==dreapta)
{ verific proprietatea...par in cazul de fata
if(v[stanga]%2==0) sol=1;
else sol=0;
} // adun 1 sau 0
daca elementul respectiv indeplineste sau nu proprietatea respectiva

(Ex. AEL numarul de elemente impare dintr-un sir)

II. Exemple in care se recomanda utilizarea acestei metode

Cautare Binara

Se considera un vector cu n elemente.
Elementele vectorului suntsortate crescator.
Sa se verifice daca o anumita valoare (val) se gaseste in vector.
In caz afirmativ , sa se afiseze pozitia pe care se gaseste,
altfel sa se afiseze 0

using namespace std;
ifstream f("div.in");
ofstream g("div.out");
int v[100],n;
void divide(int stanga, int dreapta,int &mijloc)
{
mijloc=(stanga+dreapta)/2;
}

void CautareBinara(int stanga, int dreapta, int v[],int val, int &sol)
{ int mijloc;
if(stanga>dreapta) sol=0;
else
{ divide(stanga, dreapta, mijloc);
if(val==v[mijloc]) sol=mijloc;
else
{ if(val<v[mijloc]) CautareBinara(stanga,mijloc-1,v,val,sol);
else CautareBinara(mijloc+1,dreapta, v,val,sol);

}

}
}

int main()
{ int i,sol,val;
f>>n;
for(i=1;i<=n;++i)
f>>v[i];
f>>val;
CautareBinara(1,n,v,val,sol);
g<<sol;
f.close();
g.close();
return 0;
}

QuickSort- Sortare rapida

(ca in manual....)

Varianta 2. QuickSort
(principiul arderii lumanarii la ambele capete ..principiul lui Hoare- algoritm din cartea lui Donald Knuth)

include<fstream>
using namespace std;
ifstream f("date.in");
ofstream g("date.out");
int v[100],n;
void QuickSort(int stanga, int dreapta)
{ pivot=elementul din mijloc , caut din ambele capete pozitia in care elementele nu mai sunt in ordine- variabilele i, j

int pivot, mijloc,i,j,aux;
mijloc=(stanga+dreapta)/2;
pivot=v[mijloc];i=stanga;j=dreapta;
while(i<=j)
{while(v[i]<pivot)i++;
while(v[j]>pivot) j--;
if(i<=j){aux=v[i];v[i]=v[j];v[j]=aux;i++;j--;}
}
if(stanga<j)QuickSort(stanga,j);
if(i<dreapta) QuickSort(i,dreapta);
}
QuickSort.png
int main()
{ int i;
f>>n;
for(i=1;i<=n;++i) f>>v[i];
QuickSort(1,n);
for(i=1;i<=n;++i) g<<v[i]<<" ";
f.close(); g.close();
return 0;
}
sir initial
sir initial
3 8 1 3 5 2
pivot=1
se face interschimbarea lui 3 cu 1
limitele actuale sunt: i= 2 j=2
stanga: 1 dreapta 6
1 8 3 3 5 2
limitele actuale sunt: i= 2 j=1
stanga: 1 dreapta 6
1 8 3 3 5 2
pivot=3
se face interschimbarea lui 8 cu 2
limitele actuale sunt: i= 3 j=5
stanga: 2 dreapta 6
1 2 3 3 5 8
se face interschimbarea lui 3 cu 3
limitele actuale sunt: i= 4 j=3
stanga: 2 dreapta 6
1 2 3 3 5 8
pivot=2
se face interschimbarea lui 2 cu 2
limitele actuale sunt: i= 3 j=1
stanga: 2 dreapta 3
1 2 3 3 5 8

pivot=5
se face interschimbarea lui 5 cu 5
limitele actuale sunt: i= 6 j=4
stanga: 4 dreapta 6
1 2 3 3 5 8
1 2 3 3 5 8

Turnurile din Hanoi

" Turnul din Hanoi sau Turnurile din Hanoi este un joc matematic sau puzzle. Este format din trei tije și un număr variabil de discuri, de diferite mărimi, care pot fi poziționate pe oricare din cele 3 tije. Jocul începe având discurile așezate în stivă pe prima tijă, în ordinea mărimii lor, astfel încât să formeze un turn. Scopul jocului este acela de a muta întreaga stivă de pe o tijă pe alta, respectând următoarele reguli:
  • Doar un singur disc poate fi mutat, la un moment dat.
  • Fiecare mutare constă în luarea celui mai de sus disc de pe o tija și glisarea lui pe o altă tijă, chiar și deasupra altor discuri care sunt deja prezente pe acea tijă.
  • Un disc mai mare nu poate fi poziționat deasupra unui disc mai mic "

*numărul total de mutări necesare =


NrMutari.png
https://en.wikipedia.org/wiki/Tower_of_HanoiVizualizare grafică aici

http://www.puzzle.ro/ro/play_toh.htm

http://www.anulmatematicii.ro/articol/turnul-din-hanoi

o prezentare

codul sursă

#include <iostream>
using namespace std;
long nr;
//nr= numar totale mutari
void hanoi(int n,char a,char b, char c)
{if(n==1) {cout<<a<<b<<" ";nr++;}
else
{ hanoi(n-1,a,c,b);
cout<<a<<b<<" ";
++nr;
hanoi(n-1,c,b,a);
}
}
int main()
{char a='a',b='b',c='c';
int n;
cin>>n;
hanoi(n,a,b,c);
cout<<endl<<nr;
return 0;

}

MergeSort